package com.ywger.web.aspect;

import cn.hutool.core.net.Ipv4Util;
import com.alibaba.druid.util.DruidWebUtils;
import com.alibaba.fastjson.JSON;
import com.ywger.integration.constants.log.LogFormat;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.net.IPv6Utils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import sun.net.util.IPAddressUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @author chenmeng
 * @date 2021-07-18 15:31
 * @desc
 */
@Component
@Aspect
@Slf4j
public class ControllerAspect {

    @Pointcut("execution(public * com.ywger.web.controller.*.*(..))")
    public void logPointCut(){};

    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String body = "";
        String url = getRequestUrl(request);
        if(request.getContentType()!=null && request.getContentType().contains(MediaType.MULTIPART_FORM_DATA_VALUE)){
            body =request.getContentType();
        }else{
            body = JSON.toJSONString(getRequestParams(joinPoint));
        }
        log.info(LogFormat.HTTP_REQ_FORMAT, DruidWebUtils.getRemoteAddr(request), request.getMethod(), url,
                body    );


    }

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object ob = pjp.proceed();
        stopWatch.stop();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String url = getRequestUrl(request);
        String body = "";
        if(request.getContentType()!=null && request.getContentType().contains(MediaType.MULTIPART_FORM_DATA_VALUE)){
            body =request.getContentType();
        }else{
            body = JSON.toJSONString(getRequestParams(pjp));
        }
        log.info(LogFormat.HTTP_RES_FORMAT, DruidWebUtils.getRemoteAddr(request),request.getMethod(), url,
                body,
                JSON.toJSONString(ob),stopWatch.getLastTaskTimeMillis()
        );
        return ob;
    }



    private String getRequestUrl(HttpServletRequest request) {
        String params = getQuery(request.getParameterMap());
        if(StringUtils.isEmpty(params)){
            return request.getRequestURL().toString();
        }
        return request.getRequestURL().append("?").append(params).toString();
    }


    public String getQuery(Map<String,String[]> queryParams) {
        if (!CollectionUtils.isEmpty(queryParams)) {
            StringBuilder queryBuilder = new StringBuilder();
            queryParams.forEach((name, values) -> {
                if (values.length==0) {
                    if (queryBuilder.length() != 0) {
                        queryBuilder.append('&');
                    }
                    queryBuilder.append(name);
                }
                else {
                    for (Object value : values) {
                        if (queryBuilder.length() != 0) {
                            queryBuilder.append('&');
                        }
                        queryBuilder.append(name);
                        if (value != null) {
                            queryBuilder.append('=').append(value.toString());
                        }
                    }
                }
            });
            return queryBuilder.toString();
        }
        else {
            return null;
        }
    }

    /**
     * 获取入参
     * @param proceedingJoinPoint
     *
     * @return
     * */
    private Map<String, Object> getRequestParams(JoinPoint proceedingJoinPoint) {
        Map<String, Object> requestParams = new HashMap<>();

        //参数名
        String[] paramNames =
                ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
        //参数值
        Object[] paramValues = proceedingJoinPoint.getArgs();

        for (int i = 0; i < paramNames.length; i++) {
            Object value = paramValues[i];

            //如果是文件对象
            if (value instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) value;
                value = file.getOriginalFilename();
            }

            requestParams.put(paramNames[i], value);
        }

        return requestParams;
    }
}
